import test from "./test";
/**
 * 检测参数是否不为空 结果与 isNull 相反
 */
const isNotNull = function(value) {
    return !isNull(value);
};

/**
 * 检测是否是完整的web链接，即是否带有http
 * @param {Object} str
 */
const isFullWebLink = function(str){
    // var pattern = /(https?:\/\/)/g;
    // 有很多种的协议类型，所以直接判断://
    var pattern = /:\/\//;
    return pattern.test(str)
}

/**
 * 检测参数是否为空 其中 undefined、null、{}、[]、"" 均为空值  true 空值  false 有值
 */
const isNull = function(value) {
    let key = false;
    if (
        typeof value == "undefined" ||
        Object.prototype.toString.call(value) == "[object Null]" ||
        JSON.stringify(value) == "{}" ||
        JSON.stringify(value) == "[]" ||
        value === "" ||
        JSON.stringify(value) === undefined
    ) {
        key = true;
    }
    return key;
};

/**
 * 获取数字的小数位数
 */
function getDecimalPlaces(num) {
    const numStr = num.toString();
    if (/\d(\.\d+)?(e[+-]?\d+)/i.test(numStr)) { // 科学计数法处理
        const match = numStr.match(/e([+-]?\d+)/i);
        const exponent = parseInt(match[1], 10);
        return Math.max(0, (numStr.split('.')[1] || '').length - exponent);
    }
    return (numStr.split('.')[1] || '').length;
}

/**
 * 精确加法
 */
function addition(a, b) {
    const maxScale = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
    const multiplier = Math.pow(10, maxScale);
    return (Math.round(a * multiplier) + Math.round(b * multiplier)) / multiplier;
}

/**
 * 精确减法
 */
function subtract(a, b) {
    const maxScale = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
    const multiplier = Math.pow(10, maxScale);
    return (Math.round(a * multiplier) - Math.round(b * multiplier)) / multiplier;
}

/**
 * 精确乘法
 */
function multiply(a, b) {
    const scale = getDecimalPlaces(a) + getDecimalPlaces(b);
    const multiplier = Math.pow(10, scale);
    const scaledA = Number(a.toString().replace('.', ''));
    const scaledB = Number(b.toString().replace('.', ''));
    return scaledA * scaledB / multiplier;
}

/**
 * 精确除法（保留指定位数小数）
 */
function divide(a, b, precision = 10) {
    const scale = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
    const multiplier = Math.pow(10, scale);
    const scaledA = a * multiplier;
    const scaledB = b * multiplier;
    return Number((scaledA / scaledB).toFixed(precision));
}


/**
 * 设置剪切板内容
 */
function setClipboardData(data, toast = '已复制'){
    uni.setClipboardData({
        data,
        success: function () {
            if(toast){
                uni.showToast({
                    title: toast,
                    icon: 'none'
                })
            }
        }
    });
}
/**
 * uni图片预览
 * @param {Object} current
 * @param {Object} urls
 */
const previewImage = function(current, urls){
    uni.previewImage({
        current,
        urls
    })
}

/**
 * 清除对象空属性，只返回有值 的属性
 * @param {Object} obj
 */
const removeEmptyAttr = function(obj){
    let newObj = {}
    Object.keys(obj).forEach(key => {
        if(isNotNull(obj[key])) newObj[key] = obj[key]
    })
    return newObj
}

/**
 * 拨打电话
 * @param {Object} phoneNumber 电话号码
 */
const makePhoneCall = function(phoneNumber){
    uni.makePhoneCall({ 
        phoneNumber,
        fail(e) {
            console.log(e)
        }
    })
}

/**
 * 打开导航
 * 坐标系问题：
 *  高德、腾讯使用GCJ-02坐标系
 *  百度使用BD-09坐标系
 *  微信小程序返回GCJ-02坐标
 *  若坐标来源不同需进行坐标系转换
 *  配置要求：
 *  iOS需在manifest.json配置URL Scheme白名单
 *  各大地图H5版可能需要申请对应的服务密钥
 * @param {Object} latitude
 * @param {Object} longitude
 * @param {Object} name
 */
 async function openMapNavigation(latitude, longitude, name) {
    const platform = uni.getSystemInfoSync().platform
    // APP端处理
    // #ifdef APP-PLUS
    const res = await uni.showActionSheet({
      itemList: ['高德地图', '百度地图', '腾讯地图']
    }).catch(err => {})
    
    let url = '',
        pname = '', 
        action = ''
    switch (res.tapIndex) {
        /// 直接开始导航路线
      case 0: // 高德
        url = platform == 'android'? `androidamap://route?dname=${name}&dlat=${latitude}&dlon=${longitude}&dev=0&t=0`:
                                    `iosamap://path?dname=${name}&dlat=${latitude}&dlon=${longitude}&dev=0&t=0`
        pname = 'com.autonavi.minimap'
        action = 'iosamap://'
        break
      case 1: // 百度
        // const [longitude, latitude] = gcj02tobd09(longitude, latitude)
        url = `baidumap://map/direction?destination=${ latitude },${ longitude }|${ name }&coord_type=gcj02&mode=driving`
        pname = 'com.baidu.BaiduMap'
        action = 'baidumap://'
        break
      case 2: // 腾讯
        url = `qqmap://map/routeplan?type=drive&to=${name}&tocoord=${latitude},${longitude}`
        pname = 'com.tencent.map'
        action = 'qqmap://'
        break
        
        // 只是定位
        // case 0: // 高德
        //   url = platform == 'android'? `androidamap://viewMap?poiname=${name}&lat=${latitude}&lon=${longitude}&dev=0&t=0`:
        //                               `iosamap://viewMap?poiname=${name}&lat=${latitude}&lon=${longitude}&dev=0&t=0`
        //   pname = 'com.autonavi.minimap'
        //   action = 'iosamap://'
        //   break
        // case 1: // 百度
        //   // const [lng, lat] = gcj02tobd09(longitude, latitude) 
        //   url = `baidumap://map/marker?location=${ latitude },${ longitude }&title=${ name }&coord_type=gcj02`
        //   pname = 'com.baidu.BaiduMap'
        //   action = 'baidumap://'
        //   break
        // case 2: // 腾讯
        //   url = `qqmap://map/marker?marker=coord:${ latitude },${ longitude };title:${ name };addr:${ name }` //&referer=应用Key
        //   pname = 'com.tencent.map'
        //   action = 'qqmap://'
        //   break 
    }
     
    const isInstalled = checkAppInstalled(pname, action);
    if (isInstalled) {
      plus.runtime.openURL(url);
    } else {
      uni.showToast({ title: '请先安装导航应用', icon: 'none' });
    }
    // #endif
    // H5处理

     // #ifdef H5
     const res = await uni.showActionSheet({
       itemList: ['高德地图', '百度地图', '腾讯地图']
     }).catch(err => {})
     
     let url = ''
     switch (res.tapIndex) {
       case 0:
         url = `https://uri.amap.com/navigation?to=${longitude},${latitude},${name}` //&mode=car
         break
       case 1:
         // 百度地图需要把坐标系转换成WGS-84 
         // const { lat, lng } = gcj02ToWgs84(latitude, longitude)
         // url = `https://api.map.baidu.com/direction?destination=${name}&latlng=${lat},${lng}&mode=driving`
         url = `https://api.map.baidu.com/direction?destination=${name}&latlng=${latitude},${longitude}` //&mode=driving 
         break
       case 2:
         url = `https://apis.map.qq.com/uri/v1/routeplan?type=drive&to=${name}&tocoord=${latitude},${longitude}`
         break
     }
     window.open(url)
     // #endif
    
    // 微信小程序

    // #ifdef MP-WEIXIN
    wx.openLocation({
      latitude: parseFloat(latitude),
      longitude: parseFloat(longitude),
      
      name,
      fail: (err) => {
        console.error('打开失败:', err)
      }
    })
    // #endif

}

function checkAppInstalled(pname, action) {
    // #ifdef APP-PLUS
    if(plus.runtime.isApplicationExist({ pname, action })){
        return true
    }else{
        return false
    }
    // #endif
}


// GCJ-02转BD-09
function gcj02tobd09(lng, lat) {
  const x_PI = (Math.PI * 3000.0) / 180.0;
  const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
  const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
  const bd_lng = z * Math.cos(theta) + 0.0065;
  const bd_lat = z * Math.sin(theta) + 0.006;
  return [bd_lng, bd_lat];
}


/**
 * 通过地址信息获取经纬度
 * 通过高德地图的 https://restapi.amap.com/v3/geocode/geo 接口获取的经纬度数据，
 * 默认使用的是 GCJ-02 坐标系（也称为“火星坐标系”）。这是中国国家测绘局制定的加密坐标系，与全球通用的 WGS-84 坐标系存在一定的偏移。
 * 如果需要将 GCJ-02 坐标转换为其他坐标系（如 WGS-84 或百度坐标系 BD-09），需要使用相应的转换算法或工具。
 */
function getAddressLngAsLat(address){
    return new Promise((reslove, reject) => {
        uni.request({
            url: `https://restapi.amap.com/v3/geocode/geo?address=${address}&key=${'afe7ecf3e1ea4ccc00c94471c22fbe56'}`,
            method: "get",
            timeout: 6000,
            success(res) {
                let positon = res.data.geocodes[0].location.split(',')
                reslove({
                    success: true,
                    latitude: positon[1],
                    longitude: positon[0]
                })
            },
            fail(e) {
                console.log(e);
                reject({
                    success: false
                })
            }
        });
    })
}
/**
 * 解决原生toFixed精度问题
 * @param {Object} num
 * @param {Object} decimalPlaces
 */
function toFixedString(num, decimalPlaces) {
    if(isNull(num)) return ''
    let [integerPart, decimalPart] = num.toString().split('.');
    if (decimalPart && decimalPart.length > decimalPlaces) {
        // 提取多余的位数进行四舍五入操作
        const roundingDigit = parseInt(decimalPart[decimalPlaces], 10);
        decimalPart = decimalPart.slice(0, decimalPlaces);
        if (roundingDigit >= 5) {
            decimalPart = (parseInt(decimalPart, 10) + 1).toString();
        }
    }
    return parseFloat(integerPart + '.' + decimalPart).toFixed(decimalPlaces);
}

/**
 * 全面日期格式转换函数
 * 支持连字符格式：YY-MM-DD → 25-05-06
 * @param {number|string} dateInput - 时间戳（支持秒/毫秒）或日期字符串
 * @param {string} [format='YYYY-MM-DD HH:mm:ss'] - 格式模板,支持标准格式符号：YYYY（年）、MM（月）、DD（日）、HH（时）、mm（分）、ss（秒）、SSS（毫秒，扩展功能：WW（中文周）、W（英文周缩写）
 * @returns {string} 格式化后的日期字符串
 *     
 * 时间戳测试（秒级）
 *console.log(formatDate(1746460800, 'YYYY年MM月DD日 HH:mm:ss')) // 2025年05月06日 00:00:00
 *
 * 时间戳测试（毫秒级）
 * console.log(formatDate(1746460800000, 'YYYY/MM/DD HH:mm:ss.SSS')) 
 *
 * 字符串测试（ISO格式）
 *console.log(formatDate('2025-05-06T12:34:56', 'YYYY-MM-DD HH:mm:ss')) 
 *
 * 字符串测试（iOS兼容格式）
 *console.log(formatDate('2025-05-06', 'YYYY年MM月DD日 周WW')) 
 *
 * 自定义格式测试
 *console.log(formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss.SSS'))
 */
 function formatDate(dateInput, format = 'YYYY-MM-DD HH:mm:ss') {
    if(!dateInput) return ''
    const date = parseDate(dateInput)
    if (date.toString() === 'Invalid Date') return 'Invalid Date'
    
    // 时间组件配置
    const components = {
      YYYY: date.getFullYear().toString(),
      MM: (date.getMonth() + 1).toString().padStart(2, '0'),
      DD: date.getDate().toString().padStart(2, '0'),
      HH: date.getHours().toString().padStart(2, '0'),
      mm: date.getMinutes().toString().padStart(2, '0'),
      ss: date.getSeconds().toString().padStart(2, '0'),
      SSS: date.getMilliseconds().toString().padStart(3, '0'),
      // 周相关扩展
      WW: ['日', '一', '二', '三', '四', '五', '六'][date.getDay()],
      W: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()].substr(0, 3)
    }
    
    // 高级格式化处理（支持连字符格式）
    return format.replace(/(YYYY|MM|DD|HH|mm|ss|SSS|WW|W)/g, match => {
      // 处理连字符格式（如YY-MM-DD）
      if (match.includes('-')) {
        return match.split('-').map(m => components[m] || m).join('')
      }
      return components[match] || match
    })
}

/**
 * 统一处理iOS日期格式兼容性问题，支持特殊格式：2025/06/23 16:04:12408+08:00
 * （秒与毫秒连写：12408 → 12秒408毫秒；时区+08:00 → 兼容iOS解析）、
 * @param {Date | number | string | null | undefined} input 
 */
function parseDate(input){
  // 1. 处理null/undefined（避免后续toString报错）
  if (!input) {
    return new Date(NaN); // 返回无效日期，便于外部判断
  }

  // 2. 已是Date对象直接返回
  if (input instanceof Date) {
    return input;
  }

  // 3. 处理时间戳（10位秒级/13位毫秒级）
  if (typeof input === "number") {
    const timestampStr = input.toString();
    // 10位→秒级转毫秒级，13位→直接使用（兼容常见时间戳场景）
    const millisecondTimestamp = timestampStr.length === 10 
      ? input * 1000 
      : input;
    return new Date(millisecondTimestamp);
  }

  // 4. 处理字符串类型（核心：解决“秒毫秒连写”和“时区兼容”）
  let dateStr = input.toString().trim();

  // 4.1 先处理基础格式（短横线转斜杠、T转空格，保留原有兼容）
  dateStr = dateStr
    .replace(/-/g, "/") // 2025-06-23 → 2025/06/23（兼容iOS）
    .replace(/T/g, " "); // 2025-06-23T16:04 → 2025/06/23 16:04（处理ISO格式）

  // 4.2 拆分“日期部分”和“时间+时区部分”（按空格分隔）
  const [datePart, timeWithTz = ""] = dateStr.split(" ");
  if (timeWithTz) {
    // 4.2.1 提取时区（如+08:00、-05:00，最后6个字符：±HH:mm）
    const timezoneMatch = timeWithTz.match(/([+-]\d{2}:\d{2})$/) || [];
    const timezone = timezoneMatch[1] || ""; // 匹配到的时区（如+08:00）
    let timeWithoutTz = timezone 
      ? timeWithTz.slice(0, -timezone.length) // 去掉时区后的纯时间（如16:04:12408）
      : timeWithTz;

    // 4.2.2 拆分“秒+毫秒”（最后一个冒号后是连写的秒和毫秒，如12408→12秒408毫秒）
    const timeSegments = timeWithoutTz.split(":"); // 拆分为 ["16", "04", "12408"]
    if (timeSegments.length >= 3) {
      const secMsCombined = timeSegments.pop() || ""; // 取出最后一段（秒+毫秒：12408）
      // 规则：最后3位是毫秒，前面是秒（不足3位则秒为0，如408→0秒408毫秒）
      const seconds = secMsCombined.slice(0, -3) || "0"; // 秒：12408→12
      const milliseconds = secMsCombined.slice(-3) || "000"; // 毫秒：12408→408
      // 重组时间段：时:分:秒.毫秒（如16:04:12.408）
      timeSegments.push(`${seconds}.${milliseconds}`);
      timeWithoutTz = timeSegments.join(":"); // 重组后：16:04:12.408
    }

    // 4.2.3 处理时区格式（iOS不兼容+08:00，转成+0800）
    const processedTimezone = timezone.replace(":", ""); // +08:00 → +0800

    // 4.2.4 重组完整日期字符串（如2025/06/23 16:04:12.408+0800）
    dateStr = `${datePart} ${timeWithoutTz}${processedTimezone}`;
  }

  // 5. 最终解析为Date（兼容iOS）
  const parsedDate = new Date(dateStr);
  // 兜底：若解析失败（极端格式），尝试直接用原始字符串再解析一次
  return isNaN(parsedDate.getTime()) ? new Date(input) : parsedDate;
}


/**
 * 随机字符串
 * @param {number} length 
 * @returns 
 */
const generateRandomString = (length) => {
	const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	let result = '';
	const charactersLength = characters.length;
	for (let i = 0; i < length; i++) {
		const randomIndex = Math.floor(Math.random() * charactersLength);
		result += characters[randomIndex];
	}
	return result;
}

//a 到z 排序 过滤字段  
const objectToSortedQueryString = (obj) => {
	// 判断对象是否为空
	if (obj == null || Object.keys(obj).length === 0) {
		return '';
	}

	// 过滤掉值为空字符串、null、undefined 或空数组 的键值对
	const filteredObj = Object.fromEntries(
		Object.entries(obj).filter(([key, value]) => {
			// 检查值是否为空字符串、null、undefined 或空数组
			return value !== null &&
				value !== '' &&
				value !== undefined &&
				!(Array.isArray(value) && value.length === 0);
		})
	);

	// 对剩余的键值对按键名进行字母顺序排序
	const sortedEntries = Object.entries(filteredObj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));

	// // 将排序后的键值对转换为 key1=value1&key2=value2 格式的字符串
	// const queryString = sortedEntries.map(([key, value]) => {
	// 	const encodedKey = decodeURIComponent(key);
	// 	const encodedValue = decodeURIComponent(value.toString()); // 确保值被转换为字符串并编码
	// 	return `${encodedKey}=${encodedValue}`;
	// }).join('&');


	// 将排序后的键值对转换为 key1=value1&key2=value2 格式的字符串
	const queryString = sortedEntries.filter(([key, value]) => {
		// 数组和对象不参与验证
		return !(typeof value == 'object')
	}).map(([key, value]) => {
		const encodedKey = encodeURIComponent(key);
		const encodedValue = value
		return `${encodedKey}=${encodedValue}`;
	}).join('&');

	return queryString;
}

/**
 * 显示消息提示框
 * @param {String} title 提示的内容，长度与 icon 取值有关。
 * @param {Number} duration 提示的延迟时间，单位毫秒，默认：2000
 * @param {String} icon 
 */
const toast = function (title, duration = 2000, icon = 'none'){
    uni.showToast({
        title: String(title),
        icon,
        duration
    })
}

/**
 * 根据路由地址查找页面
 * @param {String} findRoute
 */
const findPages = function(findRoute){
    let pages = getCurrentPages()
    return pages.find(page => '/' + page.route === findRoute)
}

/**
 * 打开外部链接
 * @param {String} url
 */
const openlinks = function (url){
    // #ifdef MP-WEIXIN
    uni.navigateTo({
        url: '/pages/web-view/web-view?encodeUrl=' + encodeURIComponent(url)
    })
    // #endif
    // #ifdef H5
    window.open(url)
    // #endif
    // #ifdef APP-PLUS
    plus.webview.open(url)
    // #endif
}


/**
 * 小程序订阅消息
 * @param {array} tmplIds 订阅id合集
 * @param {function} successFn 成功回调
 */
const requestSubscribeMessage = function(tmplIds, successFn){
    // #ifdef MP-WEIXIN
    uni.getSetting({
        withSubscriptions: true, // 需要设置 withSubscriptions 为 true
        success(res) {
            // 查看是否有没通过权限的订阅消息，如有则请求
            const notTmplIds = tmplIds.filter(id => !res.subscriptionsSetting[id] || res.subscriptionsSetting[id] !== 'accept')
            if(notTmplIds.length){
                // 获取未通过订阅权限
                wx.requestSubscribeMessage({
                    tmplIds: notTmplIds, // 替换为您的订阅消息模板 ID
                    success: (res) => {
                      // if (res['yourTemplateID1'] === 'accept' && res['yourTemplateID2'] === 'accept') {
                      //   // 用户同意订阅消息，可以在这里执行后续操作
                      // }
                        successFn && successFn(res)
                    },
                    fail: (errors) => {
                        console.log(errors)
                    }
                })
            }
            
        }
    })
    // #endif
}

/**
 * 映射数组label
 * @param {string|number} value
 * @param {array} array
 * @param {string} valueKey
 * @param {string} labelKey
 */
const mapArrayLabel = function(value, array, valueKey = 'id', labelKey = 'label'){
    let item = array.find(e => e[valueKey] == value)
    return item ? item[labelKey] : ''
}

/**
 * @description 数字格式化
 * @param {number|string} number 要格式化的数字
 * @param {number} decimals 保留几位小数
 * @param {string} decimalPoint 小数点符号
 * @param {string} thousandsSeparator 千分位符号
 * @returns {string} 格式化后的数字
 */
function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
    number = `${number}`.replace(/[^0-9+-Ee.]/g, '');
    const n = !isFinite(+number) ? 0 : +number;
    const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
    const sep = typeof thousandsSeparator === 'undefined' ? ',' : thousandsSeparator;
    const dec = typeof decimalPoint === 'undefined' ? '.' : decimalPoint;
    let s = '';
    
    s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.');
    const re = /(-?\d+)(\d{3})/;
    while (re.test(s[0])) {
      s[0] = s[0].replace(re, `$1${sep}$2`);
    }
    
    if ((s[1] || '').length < prec) {
      s[1] = s[1] || '';
      s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
}


/**
 * @description 去除空格
 * @param {String} str 需要去除空格的字符串
 * @param {String} pos both(左右)|left|right|all 默认both
 */
function trim(str, pos = 'both') {
    str = String(str);
    if (pos == 'both') {
      return str.replace(/^\s+|\s+$/g, '');
    }
    if (pos == 'left') {
      return str.replace(/^\s*/, '');
    }
    if (pos == 'right') {
      return str.replace(/(\s*$)/g, '');
    }
    if (pos == 'all') {
      return str.replace(/\s+/g, '');
    }
    return str;
}

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的对象
 * @returns {*} 克隆后的对象或者原值（不是对象）
 */
function deepClone(obj) {
    // 对常见的“非”值，直接返回原来值
    if ([null, undefined, NaN, false].includes(obj)) return obj;
    if (typeof obj !== 'object' && typeof obj !== 'function') {
      // 原始类型直接返回
      return obj;
    }
    const o = test.array(obj) ? [] : {};
    for (const i in obj) {
      if (obj.hasOwnProperty(i)) {
        o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
      }
    }
    return o;
}

/**
 * @description JS对象深度合并
 * @param {object} target 需要拷贝的对象
 * @param {object} source 拷贝的来源对象
 * @returns {object|boolean} 深度合并后的对象或者false（入参有不是对象）
 */
function deepMerge(target = {}, source = {}) {
    target = deepClone(target);
    if (typeof target !== 'object' || typeof source !== 'object') return false;
    for (const prop in source) {
        if (!source.hasOwnProperty(prop)) continue;
        if (prop in target) {
          if (typeof target[prop] !== 'object') {
            target[prop] = source[prop];
          } else if (typeof source[prop] !== 'object') {
            target[prop] = source[prop];
          } else if (target[prop].concat && source[prop].concat) {
            target[prop] = target[prop].concat(source[prop]);
          } else {
            target[prop] = deepMerge(target[prop], source[prop]);
          }
        } else {
          target[prop] = source[prop];
        }
    }
    return target;
}
/**
 * 解析URL为协议、带端口的域名、路径三部分
 * @param {string} url - 完整的URL地址
 * @returns {Object} 包含protocol、domain、path的对象
 */
function parseUrl(url) {
    if (!url) {
        return { protocol: '', domain: '', path: '' };
    }

    let protocol = '';
    let remaining = url;

    // 提取协议（http、https、ftp等）
    const protocolMatch = url.match(/^([a-zA-Z]+):\/\//);
    if (protocolMatch) {
        protocol = protocolMatch[1]; // 提取协议部分（如http、https）
        remaining = url.replace(protocolMatch[0], ''); // 移除协议和//
    } else {
        // 处理不标准格式（如 http:192.0.1.2 这种缺少//的情况）
        const simpleProtocolMatch = url.match(/^([a-zA-Z]+):/);
        if (simpleProtocolMatch) {
            protocol = simpleProtocolMatch[1];
            remaining = url.replace(simpleProtocolMatch[0], '');
        }
    }

    // 提取路径（从第一个/开始）
    let path = '';
    const pathIndex = remaining.indexOf('/');
    if (pathIndex !== -1) {
        path = remaining.substring(pathIndex + 1); // 去除第一个/，保留后续路径
        remaining = remaining.substring(0, pathIndex); // 剩余部分为域名+端口
    }

    // 域名包含端口（不再移除端口）
    const domain = remaining;

    return {
        protocol: protocol.toLowerCase(), // 统一转为小写（如HTTP→http）
        domain: domain,
        path: path
    };
}

/**
 * 文字显示，为了让页面不显示null NaN 这种错误显示
 * @param {String} text 
 * @param {String} candidate 备选项
 */
function txtShow(text, candidate = ''){
	return isNotNull(text) ? text : isNotNull(candidate) ? candidate : ''
}
/**
 * 解析url参数
 * @param {Object} url
 */
function parseUrlParams(url) {
    // 分离哈希部分（避免误解析哈希中的 ? 和 =）
    const hashIndex = url.indexOf('#');
    let beforeHash = url;
    let afterHash = '';
    if (hashIndex !== -1) {
        beforeHash = url.substring(0, hashIndex);
        afterHash = url.substring(hashIndex);
    }

    // 分离基础URL和查询参数
    const [base, ...queryParts] = beforeHash.split('?');
    const query = queryParts.join('?'); // 处理多个 ? 的情况
    const data = {};

    // 解析查询参数
    if (query) {
        const pairs = query.split('&');
        for (const pair of pairs) {
            const pos = pair.indexOf('=');
            let key = pos === -1 ? pair : pair.substring(0, pos);
            let value = pos === -1 ? '' : pair.substring(pos + 1);

            // 解码 + 号为空格，并处理 URI 编码
            key = decodeURIComponent(key.replace(/\+/g, ' '));
            value = decodeURIComponent(value.replace(/\+/g, ' '));

            data[key] = value;
        }
    }

    // 合并基础URL和哈希
    const pureUrl = base + afterHash;
    return {
        url: pureUrl,
        data
    };
}
export default {
    deepClone,
    deepMerge,
    trim,
    priceFormat,
    toast,
    generateRandomString,
    objectToSortedQueryString,
    toFixedString,
    gcj02tobd09,
    setClipboardData,
    addition,
    subtract,
    multiply,
    divide,
    isNotNull,
    isNull,
    isFullWebLink,
    previewImage,
    removeEmptyAttr,
    makePhoneCall,
    openMapNavigation,
    getAddressLngAsLat,
    formatDate,
    parseDate,
    findPages,
    requestSubscribeMessage,
    mapArrayLabel,
    parseUrl,
    txtShow,
    parseUrlParams
}